﻿
using System.Text.Json;

using Bee.Base.Abstractions.Navigation;
using Bee.Base.Abstractions.Plugin;
using Bee.Base.Abstractions.Tasks;
using Bee.Base.ViewModels;
using Bee.Plugin.Multimedia.Models;
using Bee.Plugin.Multimedia.Navigation.Commands;
using Bee.Plugin.Multimedia.Tasks;
using Bee.Plugin.Multimedia.ViewModels;
using Bee.Plugin.Multimedia.Views;

using FFMpegCore;

using Ke.Bee.Localization.Providers.Abstractions;

using Microsoft.Extensions.DependencyInjection;

namespace Bee.Plugin.Multimedia;

/// <summary>
/// 多媒体处理插件
/// </summary>
/// <param name="serviceProvider"></param>
public class MultimediaProcessPlugin(IServiceProvider serviceProvider) : PluginBase(serviceProvider)
{

    public override string PluginName => MultimediaProcessConsts.PluginName;

    public override void RegisterServices(IServiceCollection services)
    {
        services.AddTransient<IPlugin, MultimediaProcessPlugin>();
        services.AddSingleton<ILocalizationResourceContributor, MultimediaProcessLocalizationResourceContributor>();
        services.AddSingleton<INavigationCommand, VideoProcessNavigationCommand>();
        services.AddSingleton<INavigationCommand, AudioProcessNavigationCommand>();

        // 配置多媒体服务
        services.ConfigureMultimedia(Path.Combine(AppSettings.PluginPath, PluginName), AppSettings.TempPath);

        // 视图模型
        services.AddTransient<VideoProcessViewModel>();
        services.AddTransient<TaskListViewModel<VideoTranscodingArguments>>();
        services.AddTransient<VideoTranscodingViewModel>();
        services.AddTransient<VideoTranscodingView>();
        services.AddTransient<TaskListViewModel<VideoSnapshotArguments>>();
        services.AddTransient<VideoSnapshotViewModel>();
        services.AddTransient<VideoSnapshotView>();
        services.AddTransient<TaskListViewModel<VideoMergeArguments>>();
        services.AddTransient<VideoMergeViewModel>();
        services.AddTransient<VideoMergeView>();
        services.AddTransient<TaskListViewModel<VideoSplitArguments>>();
        services.AddTransient<VideoSplitViewModel>();
        services.AddTransient<VideoSplitView>();

        // 音频
        services.AddTransient<AudioProcessViewModel>();
        services.AddTransient<TaskListViewModel<AudioProcessArguments>>();

        // 任务处理
        services.AddTransient<ITaskHandler<VideoTranscodingArguments>, VideoTranscodingTaskHandler>();
        services.AddTransient<ITaskHandler<VideoSnapshotArguments>, VideoSnapshotTaskHandler>();
        services.AddTransient<ITaskHandler<VideoMergeArguments>, VideoMergeTaskHandler>();
        services.AddTransient<ITaskHandler<VideoSplitArguments>, VideoSplitTaskHandler>();
        services.AddTransient<ITaskHandler<AudioProcessArguments>, AudioProcessTaskHandler>();
    }
}

internal static class ServiceExtensions
{
    /// <summary>
    /// 配置多媒体服务
    /// </summary>
    /// <param name="services"></param>
    /// <returns></returns>
    public static IServiceCollection ConfigureMultimedia(this IServiceCollection services, string pluginRootPath, string tempPath)
    {
        // 配置文件
        var cfg = Path.Combine(pluginRootPath, "Configs", "multimedia.json");
        // 配置
        MultimediaOptions options;
        // 优先使用配置文件中指定的配置
        if (File.Exists(cfg))
        {
            options = JsonSerializer.Deserialize<MultimediaOptions>(File.ReadAllBytes(cfg))!;
        }
        else
        {
            options = new MultimediaOptions
            {
                FFBinPath = Path.Combine(pluginRootPath, "packages/ffmpeg-2024-11-28/bin/")
            };
        }

        var ffmpegExePath = Path.Combine(options.FFBinPath, "ffmpeg.exe");
        if (!File.Exists(ffmpegExePath)) throw new FileNotFoundException(ffmpegExePath);

        var ffprobeExePath = Path.Combine(options.FFBinPath, "ffprobe.exe");
        if (!File.Exists(ffprobeExePath)) throw new FileNotFoundException(ffprobeExePath);

        options.TempPath = Path.Combine(tempPath, MultimediaProcessConsts.PluginName);
        if (!Directory.Exists(options.TempPath)) Directory.CreateDirectory(options.TempPath);

        GlobalFFOptions.Configure(new FFOptions { BinaryFolder = options.FFBinPath, TemporaryFilesFolder = options.TempPath });

        services.AddSingleton(options);
        return services;
    }
}
